class Book < ActiveRecord::Base
  belongs_to :author
  
  validates :title, :presence => true
  validates :cover_type, :presence => true
  validate :is_valid_isbn, :if => :contains_isbn?
  
  def self.search(search)
    if search
      where('title LIKE ?', "%#{search}%")
    else
      scoped
    end
  end
  
  # Only validate when has_isbn is true, otherwise consider it free-format text
  def contains_isbn?
    has_isbn == true
  end
  
  # Validate ISBN (either 10 or 13 digits)
  def is_valid_isbn
    if is_valid_isbn10(isbn) or is_valid_isbn13(isbn)
      errors.add(:isbn, "Invalid ISBN given!")
    end
  end
  
  # Validate 10-digit ISBN
  def is_valid_isbn10(isbn_string)
    isbn_array = isbn_to_array(isbn_string)
    sum = 0
    10.times { |i| sum+=(10-i)*isbn_array[i].to_i }
    
    # Check modulus
    0 != sum.modulo(11)
  end
  
  # Validate 13-digit ISBN
  def is_valid_isbn13(isbn_string)
    isbn_array = isbn_to_array(isbn_string)
    sum = 0
    13.times { |i| sum += i.modulo(2)==0 ? isbn_array[i].to_i : isbn_array[i].to_i*3 }
    
    # Check modulus
    0 != sum.modulo(10)
  end
  
  # Transform isbn_string into array of characters.
  # Remove spaces and dashes, and replace X in ISBN with 10 for processing.
  def isbn_to_array(isbn_string)
    a = isbn_string.split(//)
    a.map! { |x| (x == 'X' or x == 'x') ? '10' : x }
    a.delete_if { |x| (x == '-' or x == ' ') }
    a
  end
end
